package utils;

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;

import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.filechooser.FileFilter;

import replay.Player;

import meadow.MeadowWrapper;
import uk.ac.nott.cs.g53dia.BeeViewer;
import uk.ac.nott.cs.g53dia.Environment;
import uk.ac.nott.cs.g53dia.Nest;
import valueobj.SimulationSettings;

public class ControlPanel extends JFrame {

  private JTextField delay;
  private JTextField beesNum;
  private JTextField duration;
  private JTextField randomSeed;
  private JTextField replayPathField;
  private JLabel timeOfDay;
  private JLabel day;
  private JLabel eggs;
  private JLabel energy;
  private int numEnergy = Nest.NEST_COST;
  private int numEggs = 0;
  private JFileChooser chooser;
  private JCheckBox gui;
  private JCheckBox record;
  private JButton start;
  private JButton reset;
  private JButton pause;
  private JButton replay;
  private JButton refresh;
  private SimulationSettings settings;
  private static ControlPanel INSTANCE;
  boolean paused = false;
  private String replayPath;

  public static void initialize(SimulationSettings settings, String label) {
    INSTANCE = new ControlPanel(settings, label);
  }

  public static synchronized ControlPanel getInstance() {
    if (INSTANCE == null) {
      throw new IllegalStateException("Initialize settings first.");
    }
    return INSTANCE;
  }

  private ControlPanel(SimulationSettings settings, String label) {
    super(label + " configuration");
    this.settings = settings;
    setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE);
    Container c = getContentPane();
    c.setLayout(new BorderLayout());
    JPanel panel = new JPanel();
    panel.setLayout(new GridLayout(0, 3));

    panel.add(new JLabel(""));
    panel.add(new JLabel(""));
    panel.add(new JLabel(""));

    panel.add(new JLabel("Tick delay: "));
    delay = new JTextField();
    panel.add(delay);
    panel.add(new JLabel(""));

    panel.add(new JLabel("Number of days:"));
    duration = new JTextField();
    panel.add(duration);
    panel.add(new JLabel(""));

    panel.add(new JLabel("Number of bees: "));
    beesNum = new JTextField();
    panel.add(beesNum);
    panel.add(new JLabel(""));

    panel.add(new JLabel("Random seed (-1 = random): "));
    randomSeed = new JTextField();
    panel.add(randomSeed);
    panel.add(new JLabel(""));

    panel.add(new JLabel("GUI: "));
    gui = new JCheckBox();
    panel.add(gui);
    panel.add(new JLabel(""));
    gui.addActionListener(new ActionListener() {

      public void actionPerformed(ActionEvent e) {
        if (gui.isSelected()) {
          if (Simulation.isStarted()) {
            Simulation.getSimulator().setBv(new BeeViewer(Simulation.getSimulator().getSwarm()));
            Simulation.getSimulator().getBv().setDefaultCloseOperation(javax.swing.JFrame.HIDE_ON_CLOSE);
            if (MeadowWrapper.getInstance() == null) {
              MeadowWrapper.initialize("Meadow", 1200, 800, Constants.GS_INITIAL_X, Constants.GS_INITIAL_Y,
                  Simulation.getSimulator().getGlobalState());
            }
            Simulation.getSimulator().setMeadow(MeadowWrapper.getInstance());
            Simulation.getSimulator().getMeadow().setVisible(true);
          }
        } else {
          if (Simulation.isStarted()) {
            Simulation.getSimulator().getBv().setVisible(false);
            Simulation.getSimulator().setBv(null);
            Simulation.getSimulator().getMeadow().setVisible(false);
            Simulation.getSimulator().setMeadow(null);
          }
        }
      }
    });

    panel.add(new JLabel("Record: "));
    record = new JCheckBox();
    panel.add(record);
    panel.add(new JLabel(""));

    panel.add(new JLabel("Replay: "));
    replayPathField = new JTextField("none");
    replayPathField.setEnabled(false);
    panel.add(replayPathField);
    replay = new JButton("Browse..");
//    replay.setPreferredSize(new Dimension(30, 21));
    panel.add(replay);

    panel.add(new JLabel(""));
    panel.add(new JLabel(""));
    panel.add(new JLabel(""));

    JPanel butPanel = new JPanel();
    start = new JButton("Start");
    butPanel.add(start);

    reset = new JButton("Reset Values");
    butPanel.add(reset);

    pause = new JButton("Pause");
    pause.setPreferredSize(new Dimension(100, 25));
    butPanel.add(pause);

    refresh = new JButton("Refresh");
    butPanel.add(refresh);

    JButton exit = new JButton("Exit");
    butPanel.add(exit);

    timeOfDay = new JLabel(String.valueOf(Constants.STARTING_TIME % Environment.DAY_LENGTH));
    butPanel.add(new JLabel("time: "));
    timeOfDay.setPreferredSize(new Dimension(60, 20));
    butPanel.add(timeOfDay);

    day = new JLabel(String.valueOf(Constants.STARTING_TIME / Environment.DAY_LENGTH));
    butPanel.add(new JLabel("day: "));
    day.setPreferredSize(new Dimension(25, 20));
    butPanel.add(day);

//    eggs = new JLabel(String.valueOf(numEggs));
    eggs = new JLabel("0");
    butPanel.add(new JLabel("eggs: "));
    eggs.setPreferredSize(new Dimension(40, 20));
    butPanel.add(eggs);
    
    energy = new JLabel("0");
    energy.setPreferredSize(new Dimension(60, 20));
    butPanel.add(new JLabel("food: "));
    butPanel.add(energy);

    reset.addActionListener(new ActionListener() {

      public void actionPerformed(ActionEvent e) {
        setSettings(ControlPanel.this.settings);
        duration.setEnabled(true);
        beesNum.setEnabled(true);
        randomSeed.setEnabled(true);
        record.setSelected(true);
        record.setEnabled(true);
        replayPath = null;
        replayPathField.setText("none");
      }
    });
    start.addActionListener(new ActionListener() {

      public void actionPerformed(ActionEvent e) {
        getSettings();
      }
    });
    pause.addActionListener(new ActionListener() {

      public void actionPerformed(ActionEvent e) {
        ControlPanel.this.handlePause();
      }
    });
    refresh.addActionListener(new ActionListener() {

      public void actionPerformed(ActionEvent e) {
        Simulation.getSimulator().setDelay(Integer.parseInt(delay.getText()));
        Simulation.getSimulator().setDuration(Integer.parseInt(duration.getText()));
      }
    });
    exit.addActionListener(new ActionListener() {

      public void actionPerformed(ActionEvent e) {
        if (Simulation.getSimulator().getEnv() != null){
          Simulation.getSimulator().results();
          Simulation.getSimulator().clean();
        }
        System.exit(0);
      }
    });
    replay.addActionListener(new ActionListener() {

      public void actionPerformed(ActionEvent e) {
        chooseFile();
        if (replayPath != null /* && TODO: validate */) {
          duration.setEnabled(false);
          beesNum.setEnabled(false);
          randomSeed.setEnabled(false);
          record.setSelected(false);
          record.setEnabled(false);
          if (Constants.DEBUG) {
            System.out.println(replayPath);
          }
          Simulation.getSimulator().setPlayer(new Player(replayPath));
          Simulation.getSimulator().setPlaying(true);
        }
      }
    });

    c.add(panel, BorderLayout.CENTER);
    c.add(butPanel, BorderLayout.SOUTH);
    setSettings(settings);
    setResizable(false);
    setLocationRelativeTo(null);
    pack();
    setVisible(true);
    Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
  }

  public void handlePause() {
    Simulation.pause();
    if (paused) {
      pause.setText("pause");
    } else {
      pause.setText("continue");
    }
    paused = !paused;
  }

  private void chooseFile() {
    chooser = new JFileChooser(new File(".").getAbsoluteFile());
    chooser.setAcceptAllFileFilterUsed(false);
    chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
    FileFilter filter = new FileFilter() {

      public boolean accept(File f) {
        if (f.isDirectory()) {
          return true;
        }
        String s = f.getName();
        String ext = null;
        int i = s.lastIndexOf('.');
        if (i > 0 && i < s.length() - 1) {
          ext = s.substring(i + 1).toLowerCase();
        }
        return "txt".equals(ext);
      }

      @Override
      public String getDescription() {
        return "txt file";
      }
    };
    chooser.addChoosableFileFilter(filter);
    int returnVal = chooser.showOpenDialog(this);
    if (returnVal == JFileChooser.APPROVE_OPTION) {
      replayPath = null;
      try {
        replayPath = chooser.getSelectedFile().getCanonicalPath();
        replayPathField.setText(replayPath);
      } catch (IOException ex) {
        ex.printStackTrace();
      }
    }
  }

  public synchronized SimulationSettings getSettings() {
    SimulationSettings settings = new SimulationSettings();
    boolean bGui = false;
    try {
      int iDelay = Integer.parseInt(delay.getText());
      int iDuration = Integer.parseInt(duration.getText());
      int iBeesNum = Integer.parseInt(beesNum.getText());
      long lRandSeed = Integer.parseInt(randomSeed.getText());
      bGui = gui.isSelected();
      boolean bRec = record.isSelected();
      settings.setTick(iDelay);
      settings.setDuration(iDuration);
      settings.setBeesNum(iBeesNum);
      settings.setRandomSeed(lRandSeed);
      settings.setGui(bGui);
      settings.setRecord(bRec);
      settings.setBeeClass(this.settings.getBeeClass());
    } catch (NumberFormatException nfe) {
      JOptionPane.showMessageDialog(this, "Wrong format, please insert a number.");
      return null;
    }
    Simulation.setStarted(true);
    // init meadow here
//    if (bGui) {
//      MeadowWrapper.initialize("Meadow", 1200, 800, Constants.GS_INITIAL_X, Constants.GS_INITIAL_Y);
//    }
    setAllDisabled();
    notifyAll();
    return settings;
  }

  private void setSettings(SimulationSettings settings) {
    delay.setText(String.valueOf(settings.getTick()));
    duration.setText(String.valueOf(settings.getDuration()));
    beesNum.setText(String.valueOf(settings.getBeesNum()));
    gui.setSelected(settings.isGui());
    record.setSelected(settings.isRecord());
    randomSeed.setText(String.valueOf(settings.getRandomSeed()));
  }

  public void setStartEnabled() {
    start.setEnabled(true);
    reset.setEnabled(true);
    beesNum.setEnabled(true);
    randomSeed.setEnabled(true);
    replay.setEnabled(true);
    replay.setEnabled(true);
    replayPath = null;
    replayPathField.setText("none");
  }

  public void setAllDisabled() {
    start.setEnabled(false);
    reset.setEnabled(false);
    beesNum.setEnabled(false);
    randomSeed.setEnabled(false);
    record.setEnabled(false);
    replay.setEnabled(false);
  }

  public void setTimestep(long timestep) {
    this.timeOfDay.setText(String.valueOf(timestep % Environment.DAY_LENGTH));
    this.day.setText(String.valueOf(timestep / Environment.DAY_LENGTH));
  }

  public synchronized void addEgg() {
    this.numEggs++;
    this.eggs.setText(String.valueOf(numEggs));
    addEnergy(-Nest.EGG_COST);
  }
  
  public synchronized void addEnergy(int amount) {
    this.numEnergy += amount;
    this.energy.setText(String.valueOf(numEnergy));
  }
  
  public int getEnergy() {
    return this.numEnergy;
  }
  
  public int getEggs() {
    return this.numEggs;
  }
  
  public void setRandomSeed(String randomSeed) {
    this.randomSeed.setText(randomSeed);
  }
  
  public void setNumBees(String numBees) {
    this.beesNum.setText(numBees);
  }
  
  public void setDuration(String duration) {
    this.duration.setText(duration);
  }
}
